import json
import os
import csv
from PyQt5.QtWidgets import (
    QPushButton,
    QGridLayout,
    QGroupBox,
    QHeaderView,
    QHBoxLayout,
    QVBoxLayout,
    QLabel,
    QStyledItemDelegate,
    QDesktopWidget,
    QPushButton,
    QFileDialog,
    QComboBox,
    QFrame,
    QScrollArea,
    QAbstractItemView,
    QTableWidgetItem,
    QTableWidget,
    QSpacerItem,
    QSizePolicy,
)
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QObject, QEvent
from PyQt5.QtGui import QPainter, QPen, QColor, QDoubleValidator, QPixmap, QIcon
from pydantic import BaseModel, Field, field_validator
import gui.controls.envs as envs
import pandas as pd

# import gui.controls.envs as envs
from ..dlg_mulit_instance import DlgMutliInstance
from ..custom_table import CustomTable
from .. import message_box as MBox
from ..util.file_operation import FileOperation
from ..custom_widget import LineEditFloat, LineEditStr, LineEditInt, SelectBox
from ..util import data_clear as DC
from ..util import util_key_map
from enum import Enum


class LineEditFloatLimitDecimals2(LineEditFloat):
    def __init__(self, parent=None, data={}, scope=[], decimals=None):
        super().__init__()

    def _set(self, value: float = None):
        if value is None:
            value = ""
        try:
            value = "{:.2f}".format(float(value))
            # value = str(round(float(value), 2))
        except ValueError:
            value = ""

        self.setText(str(value))


# 针对寿命值清空空行
def clearStatisticsList(data):
    isStop = False
    while not isStop and len(data) > 0:
        if data[-1][0] == "" or data[-1][0] == None:
            data.pop()
        else:
            isStop = True


class FloatValidatorDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super(FloatValidatorDelegate, self).__init__(parent)
        self.validator = QDoubleValidator(self)

    def createEditor(self, parent, option, index):
        editor = super(FloatValidatorDelegate, self).createEditor(parent, option, index)
        editor.setValidator(self.validator)
        return editor


# 定义 Pydantic 模型
class LifeAnalysisModel(BaseModel):

    presetModelPath: str = Field(
        description="预设模型路径",
        alias="presetModelPath",
        required=False,
        extra={"button": [{"name": "importPresetModel", "title": "浏览"}]},
    )
    shapeParameter: int = Field(
        description="形状参数",
        alias="shapeParameter",
        required=False,
    )

    specimenCoefficient: float = Field(
        description="试件系数",
        alias="specimenCoefficient",
        required=False,
    )
    confidenceCoefficient: float = Field(
        description="置信系数",
        alias="confidenceCoefficient",
        required=False,
    )
    reliabilityCoefficient: float = Field(
        description="可靠性系数",
        alias="reliabilityCoefficient",
        required=False,
    )


class DlgLifeAnalysis(DlgMutliInstance):
    lifeAnalysis_save_signal = pyqtSignal(object)
    lifeAnalysis_calculate_signal = pyqtSignal(object)

    def __init__(self, parent=None):
        super(DlgLifeAnalysis, self).__init__(parent)

        self.isLoad = False

        self.setWindowTitle("寿命分析")
        self.resize(400, 430)
        layout = QVBoxLayout()

        contentLayout = QVBoxLayout()
        contentLayout.setSpacing(10)
        self.widgetDict = {}
        self.gridLayout = QGridLayout()
        self.gridLayout.setColumnStretch(0, 2)
        self.gridLayout.setColumnStretch(1, 3)
        self.modelToGridLayout(LifeAnalysisModel, self.gridLayout)

        statisticsGroupBox = QGroupBox("寿命统计情况")
        statisticsLayout = QVBoxLayout()
        btnLayout = QHBoxLayout()
        importBtn = QPushButton("导入")
        importBtn.clicked.connect(self.on_importBtn_clicked)
        btnLayout.addWidget(importBtn)
        btnLayout.addStretch()

        addBtn = QPushButton(self)
        self.set_button_image(addBtn, "icons/add.png")

        addBtn.clicked.connect(self.addStatistics)
        btnLayout.addWidget(addBtn)

        delBtn = QPushButton(self)
        self.set_button_image(delBtn, "icons/del.png")
        delBtn.clicked.connect(self.delStatistics)

        cfgIndex = {}
        with open("config/sys/index.json", "r", encoding="utf-8") as file:
            cfgIndex = json.load(file) or {}

        theme = cfgIndex.get("theme", "dark")  # dark or light
        if theme == "light":
            delBtn.setStyleSheet(
                """
                QPushButton {
                    background-color: #409eff;
                    border: none;
                }
            """
            )
            addBtn.setStyleSheet(
                """
                QPushButton {
                    background-color: #409eff;
                    border: none;
                }
            """
            )

        btnLayout.addWidget(delBtn)

        statisticsLayout.addLayout(btnLayout)

        self.widgetDict["statisticsTable"] = CustomTable(
            rows=0, columns=1, useCustomMenu=False
        )
        self.widgetDict["statisticsTable"].setHorizontalHeaderLabels(["寿命值"])
        self.widgetDict["statisticsTable"].verticalHeader().setVisible(True)
        self.widgetDict["statisticsTable"].rowSetFloat([0])
        statisticsLayout.addWidget(self.widgetDict["statisticsTable"])
        label = QLabel("寿命分析结果")
        self.widgetDict["lifeAnalysisResults"] = LineEditFloatLimitDecimals2(decimals=2)
        self.widgetDict["lifeAnalysisResults"].textChanged.connect(
            self.check_analysisResult
        )
        computeBtn = QPushButton("计算")
        computeBtn.clicked.connect(self.on_computeBtn_clicked)
        resLayout = QHBoxLayout()
        resLayout.addWidget(label)
        resLayout.addWidget(self.widgetDict["lifeAnalysisResults"])
        resLayout.addWidget(computeBtn)
        resLayout.setStretchFactor(label, 2)
        resLayout.setStretchFactor(self.widgetDict["lifeAnalysisResults"], 3)

        statisticsGroupBox.setLayout(statisticsLayout)

        contentLayout.addLayout(self.gridLayout)
        contentLayout.addWidget(statisticsGroupBox)
        contentLayout.addLayout(resLayout)

        self.widgetDict["importPresetModel"].clicked.connect(self.on_importCae_clicked)

        btnLayout = QHBoxLayout()
        btnLayout.setAlignment(Qt.AlignCenter)  # 设置居中对齐
        self.pBtnOK = QPushButton("保存")
        self.pBtnOK.setObjectName("pBtnOK")
        self.pBtnOK.clicked.connect(self.on_pBtnOK_clicked)
        pBtnCancel = QPushButton("取消")
        pBtnCancel.setObjectName("pBtnCancel")
        pBtnCancel.clicked.connect(self.close)
        btnLayout.addWidget(self.pBtnOK)
        btnLayout.addWidget(pBtnCancel)
        self.pBtnOK.setFocusPolicy(Qt.NoFocus)
        pBtnCancel.setFocusPolicy(Qt.NoFocus)

        # layout.addWidget(groupBox)
        layout.addLayout(contentLayout)
        layout.addLayout(btnLayout)
        self.setLayout(layout)

        self.cacheFile = "data/ipimas/uis/lifeAnalysis.json"
        # self.loadData()

    # def showEvent(self, event):
    #     super().showEvent(event)
    #     self.pBtnOK.setFocus()  # 在窗口显示后设置焦点

    def init(self, data):
        # data = util_key_map.convertKey(data, 0)
        self.loadData(data)

    def modelToGridLayout(self, model, gridLayout):
        fileds = model.model_fields
        for row, (field_name, field_info) in enumerate(fileds.items()):
            buttonList = []
            if field_info.json_schema_extra.get(
                "extra"
            ) and field_info.json_schema_extra.get("extra").get("button"):
                buttonList = field_info.json_schema_extra.get("extra").get("button")
            label = QLabel(field_info.description)
            gridLayout.addWidget(label, row, 0)
            if issubclass(field_info.annotation, Enum):
                self.widgetDict[field_name] = SelectBox(
                    options=[
                        {"title": item.alias, "value": item.alias}
                        for item in list(field_info.annotation)
                    ]
                )
                self.widgetDict[field_name].setMinimumWidth(100)
            else:
                field_type = field_info.annotation
                if field_type is float:
                    widget = LineEditFloat()
                elif field_type is int:
                    widget = LineEditInt()
                else:
                    widget = LineEditStr()
                widget.setPlaceholderText(f"请输入{field_info.description}")
                self.widgetDict[field_name] = widget
            if buttonList:
                gridLayout.addWidget(self.widgetDict[field_name], row, 1)
            else:
                gridLayout.addWidget(self.widgetDict[field_name], row, 1, 1, 2)
            for i, btnItem in enumerate(buttonList):
                self.widgetDict[btnItem.get("name")] = QPushButton(btnItem.get("title"))
                gridLayout.addWidget(self.widgetDict[btnItem.get("name")], row, 2)
            # if row != 0:
            #     spacer = QSpacerItem(20, 100, QSizePolicy.Minimum, QSizePolicy.Expanding)
            #     gridLayout.addItem(spacer, 2*row-1, 0, 1)  # 在第1行添加一个占位符，占据第0列和第1列

    def addStatistics(self, event):
        self.widgetDict["statisticsTable"].add()

    def delStatistics(self, event):
        self.widgetDict["statisticsTable"].delete()

    def check_analysisResult(self):
        if not self.isLoad:
            return
        text = self.widgetDict["lifeAnalysisResults"].getValue()
        if text:
            try:
                value = float(text)
                if value < 1.0 or value > 100000.0:
                    MBox.warning("该算法不适用于低周疲劳")
            except:
                self.widgetDict["lifeAnalysisResults"].setValue("")
                MBox.warning("请输入正确的值")

    def on_importCae_clicked(self):
        # 创建QFileDialog对话框实例
        file_dialog = QFileDialog()
        file_dialog.setNameFilter("CAE files (*.cae)")

        # 设置对话框标题
        file_dialog.setWindowTitle("选择预设模型文件")
        # 显示对话框并获取用户选择的文件
        if file_dialog.exec_():
            # 用户点击了“打开”或“保存”，获取选中的文件路径
            file_path = file_dialog.selectedFiles()[0]
            self.widgetDict["presetModelPath"].setText(file_path)

    def updateCalculateRes(self, value):

        try:
            value = "{:.2f}".format(float(value))
            if value == "0.00":
                MBox.warning("当前计算结果数值过小，经四舍五入保留两位小数后显示为0.00")
        except ValueError:
            print("err")
            pass
        self.widgetDict["lifeAnalysisResults"].setValue(value)

    def on_computeBtn_clicked(self):
        Y = self.widgetDict["statisticsTable"].getTableData()
        Y = [item for sublist in Y for item in sublist]
        Sm = self.widgetDict["shapeParameter"].getValue()
        St = self.widgetDict["specimenCoefficient"].getValue()
        Sc = self.widgetDict["confidenceCoefficient"].getValue()
        Sr = self.widgetDict["reliabilityCoefficient"].getValue()
        data = {"Y": Y, "Sm": Sm, "St": St, "Sc": Sc, "Sr": Sr}
        # print("123123=", data)
        self.lifeAnalysis_calculate_signal.emit(data)

    def on_importBtn_clicked(self):
        file_dialog = QFileDialog()
        file_dialog.setNameFilter("CSV files (*.csv)")
        # 设置对话框标题
        file_dialog.setWindowTitle("选择csv文件")
        # 显示对话框并获取用户选择的文件
        if file_dialog.exec_():
            # 用户点击了“打开”或“保存”，获取选中的文件路径
            file_path = file_dialog.selectedFiles()[0]
            self.loadCsv(file_path)

    # def load_excel(self, filePath):
    #     try:
    #         data = []
    #         excelData = pd.read_excel(filePath, header=0, usecols=["寿命值"])
    #         for index, row in excelData.iterrows():
    #             data.append([
    #                 row["寿命值"],
    #             ])
    #         self.widgetDict['statisticsTable'].addMulitRows(data)
    #     except FileNotFoundError:
    #         print(f"Error: 文件 '{filePath}' 未找到.")

    def loadCsv(self, filePath):
        try:
            with open(
                filePath, newline="", encoding="utf-8"
            ) as csvfile:  # 确保使用正确的编码
                reader = csv.reader(csvfile)
                csvData = list(reader)
                csvData = [row for row in csvData if row]
                # 如果第一行是对应的表头则删除
                del csvData[0]
                self.widgetDict["statisticsTable"].addMulitRows(csvData)

        except FileNotFoundError:
            print(f"Error: 文件 '{filePath}' 未找到.")

    def loadData(self, data):
        if data is None:
            self.isLoad = True
            return
        data = util_key_map.convertKey(data, 0, True)
        for key, value in data.items():
            if isinstance(self.widgetDict[key], CustomTable):
                self.widgetDict[key].addMulitRows(value)
            elif not isinstance(self.widgetDict[key], QPushButton):
                self.widgetDict[key].setValue(value)
        self.isLoad = True

    def on_pBtnOK_clicked(self):
        self.pBtnOK.setFocus()
        data = {}
        for key, widget in self.widgetDict.items():
            if isinstance(widget, CustomTable):
                data[key] = widget.getTableData()
                clearStatisticsList(data[key])
            elif not isinstance(widget, QPushButton):
                data[key] = widget.getValue()

        data = util_key_map.convertKey(data, 1, True)
        # print("123=", data)
        FileOperation.write_json(self.cacheFile, data)
        # pMap = parameterMapping()
        # descriptData = {}
        # for k, v in data.items():
        #     if k == "statisticsTable":
        #         nv = [item if item != "" else None for sublist in v for item in sublist]
        #         descriptData[pMap[k]] = nv
        #     else:
        #         descriptData[pMap[k]] = v
        # data = DC.filter_empty_values(data)
        self.close()
        self.lifeAnalysis_save_signal.emit(data)

    # def set_button_image(self, button, image_path):
    #     """设置按钮的图片，并保持等比宽高"""
    #     pixmap = QPixmap(image_path)
    #     if pixmap.isNull():
    #         print("Error: Unable to load image.")
    #         return

    #     # 等比缩放图片到指定大小（15x15像素）
    #     scaled_pixmap = pixmap.scaled(15, 15, Qt.KeepAspectRatio, Qt.SmoothTransformation)

    #     # 将 QPixmap 转换为 QIcon
    #     icon = QIcon(scaled_pixmap)

    #     # 设置按钮图标和大小
    #     button.setIcon(icon)  # 使用 QIcon 设置图标
    #     button.setIconSize(scaled_pixmap.size())  # 设置图标大小
    #     button.setFixedSize(15, 15)  # 强制设置按钮的宽高为15像素

    def set_button_image(self, button, image_path):
        """设置按钮的图片，并保持等比宽高，同时设置边距"""
        pixmap = QPixmap(image_path)
        if pixmap.isNull():
            print("Error: Unable to load image.")
            return

        # 等比缩放图片到指定大小（15x15像素）
        scaled_pixmap = pixmap.scaled(
            15, 15, Qt.KeepAspectRatio, Qt.SmoothTransformation
        )

        # 将 QPixmap 转换为 QIcon
        icon = QIcon(scaled_pixmap)

        # 设置按钮图标和大小
        button.setIcon(icon)  # 使用 QIcon 设置图标
        button.setIconSize(scaled_pixmap.size())  # 设置图标大小
        button.setFixedSize(20, 20)  # 强制设置按钮的宽高为25像素（15 + 2 * 5）

        # 设置按钮的样式表，添加5像素的边距
        # button.setStyleSheet("QPushButton { padding: 5px; border: 1px solid black; }")


def toFloat(value):
    try:
        return float(value)
    except ValueError:
        return None


def parameterMapping():
    return {
        "presetModelPath": "预设模型路径",
        "shapeParameter": "形状参数",
        "specimenCoefficient": "试件系数",
        "confidenceCoefficient": "置信系数",
        "reliabilityCoefficient": "可靠性系数",
        "lifeAnalysisResults": "寿命统计结果",
        "statisticsTable": "寿命统计情况",
    }


def listToDict(list, keys):
    dataList = []
    for li in list:
        dict = {}
        for i, item in enumerate(li):
            if item or item == 0:
                dict[keys[i]] = item
        dataList.append(dict)
    return dataList
